/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * Licensed under Simplified BSD License
 *
 *  
 *  
 *
 * @Original Author: jin Chen
 * @date: Feb 16, 2005$
 * @version: 1.0
 */
package edu.psu.geovista.app.visualclassifier.classify.v2.agent;

import edu.psu.geovista.app.visualclassifier.classify.v2.ESVisualClassifier;
import edu.psu.geovista.app.visualclassifier.classify.v2.gui.LegendControl;
import edu.psu.geovista.app.visualclassifier.classify.v2.gui.LegendControl2;
import edu.psu.geovista.classification.ClassificationResult;
import edu.psu.geovista.classification.setting.ClassifySetting;
import edu.psu.geovista.classification.setting.ClassifySetting1D;
import edu.psu.geovista.data.geog.DataSetForApps;
import edu.psu.geovista.data.geog.utils.AttributesNameIndexs;
import edu.psu.geovista.data.model.AppDataModel;
import edu.psu.geovista.data.model.MetaData;
import edu.psu.geovista.ui.event.*;
import epoviz.trex.common.swing.components.combobox.TpComboBox;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Map;

public class ClassifyAgent implements ClassificationResultListener,ActionListener{
    private boolean actonComboBox;//  
    protected MyComboBox xcb; //set what variable to display on X Axis
    protected MyComboBox ycb; //set what variable to display on Y Axis

   
    AttributesNameIndexs attIndex;//keep index of attributes of data

    ClassificationInterestor hostComponent;
    LegendControl2 legendInterative;



    public ClassifyAgent(ClassificationInterestor host) {
        hostComponent=host;
        legendInterative = new LegendControl2(LegendControl2.getSampleColors());

        xcb = new MyComboBox();
        ycb = new MyComboBox();

        this.addActionListener(this);

        if(host instanceof SelectionListener){
            LegendControl2 legd=(LegendControl2) legendInterative;
            DefaultEventSupport eventSupport = legd.getEventSupport();
            eventSupport.addSelectionListener((SelectionListener)host);
        }
        //setup host to listen the default vc ( which is internally generated)
        ESVisualClassifier vc = legendInterative.getVisualClassifier();
        vc.addClassificationResultListener((ClassificationResultListener) host);
        vc.addColorArrayListener((ColorArrayListener) host);
       
    }

    /*******************************************************************************************************
     *                services
     *******************************************************************************************************/
    public int[] getIndexs(String xvarname,String yvarname){
        if(attIndex==null)return new int[0];//initially
        int xindex =this.attIndex.getIndex(xvarname);
        int yindex =this.attIndex.getIndex(yvarname);
        /**
         *  
         *  
         */
        if(xindex<0){
            xindex=1;  // 
        }
        if(yindex<0){
            yindex=2;

        }
        if(yindex==xindex){
                yindex=yindex+1;
                if(yindex>=attIndex.getAttributes().length ){
                    yindex=yindex-2;
                }
         }
        return new int[]{xindex,yindex};
    }
     public void addActionListener(ActionListener l){
         //ComboBoxEditor xed = xcb.getEditor();
         //BasicComboBoxRenderer rd = (BasicComboBoxRenderer) xcb.getRenderer();

       // rd.add

         /*ComboBoxEditor yed = ycb.getEditor();
         yed.addActionListener(l);*/
         this.xcb.addActionListener(l);
         this.ycb.addActionListener(l);

     }
    /*******************************************************************************************************
     *                setting & get
     *******************************************************************************************************/
    /**
     * Update selections on the ComboBox.
     *  
     * @param xn  x variable name
     * @param yn  y variable name
     */
    public void setVariables(String xn,String yn){
        this.setActonComboBox(false); // 
        if(xn!=null) this.xcb.setSelectedItem(xn);     //setSelectedItemQuitely
        if(xn!=null) this.ycb.setSelectedItem(yn);      //setSelectedItemQuitely
        this.setActonComboBox(true);
    }
    /**
     * get the ComboxBox only for purpose of  putting it in toolbar.
     *   
     * @return
     */
     public JComboBox getXcb() {
        return xcb;
    }
    /**
     * get the ComboxBox only for purpose of  putting it in toolbar.
     *   
     * @return
     */
    public JComboBox getYcb() {
        return ycb;
    }
    public void setYEnable(boolean enable){
        this.ycb.setEnabled(enable);
    }

    public LegendControl getLegendInterative() {
        return legendInterative;
    }


     public void setVisualClassifier(ESVisualClassifier vc) {
        this.legendInterative.setVisualClassifier(vc);
         //vc.addClassificationResultListener(this.legendStatic);

    }
    public ESVisualClassifier getVisualClassifier (){
     return legendInterative.getVisualClassifier();
}
    /*******************************************************************************************************
     *                support
     *******************************************************************************************************/

    /**
     *  
     * @param dataSet
     */
    public void setDataSet(DataSetForApps dataSet) {
        this.setActonComboBox(false);   // 

        this.attIndex =new AttributesNameIndexs(dataSet);
         String[] attributeArrays = attIndex.getAttributes();

        Arrays.sort(attributeArrays);
        //attributeArrays=new String []{"Pop1990","PopSqMi"};
        /*  
        ComboBoxModel modelx =new DefaultComboBoxModel(attributeArrays);
        xcb.setModel(modelx);
        ComboBoxModel modely =new DefaultComboBoxModel(attributeArrays);
        ycb.setModel(modely);*/
        try {
            setNameLists(xcb,attributeArrays);
            setNameLists(ycb,attributeArrays);
            int itemcount = ycb.getModel().getSize();
            if(itemcount>=1)
                ycb.setSelectedIndex(1); //Since scatter plot set it as 1 initially
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
         this.setActonComboBox(true);
    }
     /**
     *  
     * @param datamodel
     */
    public void setDataModel(AppDataModel datamodel){
        this.setActonComboBox(false);   // 
        this.attIndex =new AttributesNameIndexs(datamodel.getColumnNames() );
        String[] attributeArrays = attIndex.getAttributes();
        Arrays.sort(attributeArrays);

        try {
            setNameLists(xcb,attributeArrays);
            setNameLists(ycb,attributeArrays);
            if(ycb.getModel().getSize() >=2)
                ycb.setSelectedIndex(1); //Since scatter plot set it as 1 initially
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        //set item description

        MetaData meta = datamodel.getMetaData();
        if(meta!=null){
        Map columnDesc = meta.getColumndescription();
        xcb.setItemDescs(columnDesc);
        ycb.setItemDescs(columnDesc);
            legendInterative.setVariableDescriptions(columnDesc);
        }
        this.setActonComboBox(true);

         ESVisualClassifier vc = legendInterative.getVisualClassifier();
         if(vc!=null)
         vc.setDataModel(datamodel);
     }

    private  static void setNameLists(JComboBox cmb, String [] names){
        DefaultComboBoxModel model = (DefaultComboBoxModel) cmb.getModel();
        model.removeAllElements();

        for (int i=0;i<names.length ;i++){
            model.addElement(names[i]);

        }
    }

    /*******************************************************************************************************
     *                events
     *******************************************************************************************************/
    public void classificationResultChanged(ClassificationResultEvent e) {
         ClassificationResult cr = e.getClassificationResult();
        if(cr==null)return;

        ((ClassificationResultListener)this.legendInterative).classificationResultChanged(e);

        int colcount = cr.getNumberOfClassX(); //num of category in x direction , it is actually # of column in a legend
        int rowcount = cr.getNumberOfClassY();//num of category in y direction , it is actually # of row in a legend


        if(colcount>0&&rowcount>0){//2 dimension
            String[] attNames = cr.getAttNames();
            if(attNames==null||attNames.length  <2) assert false;
            String xn = attNames[0];
            String yn = attNames[1];
            hostComponent.setVariables(xn,yn);
            this.setVariables(xn,yn);

        }//if
        else if(colcount>0){//1 dimension
           String[] attNames = cr.getAttNames();
            if(attNames==null||attNames.length  <1) assert false;
            String xn = attNames[0];
            String yn = (String) this.getYcb().getSelectedItem() ;
            hostComponent.setVariables(xn,yn);
            this.setVariables(xn,yn);
        }//else
        

    }

    public void actionPerformed(ActionEvent e) { // 
        if(!this.isActonComboBox() )return;
        //update classification setting
        Object source = e.getSource();
        final ClassifySetting[] settings;//=new ClassifySetting1D(); //settings

        String var=null;

        //update hostcomponent to display selected variables
        String xvar = (String) getXcb().getSelectedItem();
        String yvar = (String) getYcb().getSelectedItem();
        if(xvar!=null&&yvar!=null){
            hostComponent.setVariables(xvar,yvar);
        }
        //get settings
        /*if(source==getXcb()){
        var = (String) getXcb().getSelectedItem();
        setting.setDimensionName(ClassifySetting1D.DIMENSION_NAME_X);
        }
        else if (source==getYcb()){
        var = (String) getYcb().getSelectedItem();
        setting.setDimensionName(ClassifySetting1D.DIMENSION_NAME_Y);
        }*/
        settings=this.createSetting(source);
        for (int i=0;i<settings.length ;i++){

                ClassifySetting setting= settings[i];
              if( setting instanceof ClassifySetting1D){//a setting related to variable
                    setting.setType(ClassifySetting.TYPE_VARIABLE);
                    //((ClassifySetting1D)setting).setVariableName(var);
                }
                else{
                    //a setting to swich uni-var, bi-var...
                }
                legendInterative.doClassification(setting); // 
                //doClassification(setting);

        }

    }

    /* no need to do separated thread
    protected void doClassification(final ClassifySetting setting) {
        SwingUtilities.invokeLater(new Runnable(){

            public void run() {
                legend.doClassification(setting);
            }
        });
    }*/

    /**
     * based on source of action event, determine the type of classifysetting
     * @param source
     * @return
     */
    protected ClassifySetting[] createSetting(Object source){
        final ClassifySetting1D setting=new ClassifySetting1D();
        String var=null;
        if(source==getXcb()){
             var = (String) getXcb().getSelectedItem();
            setting.setDimensionName(ClassifySetting1D.DIMENSION_NAME_X);
        }
        else if (source==getYcb()){
             var = (String) getYcb().getSelectedItem();
            setting.setDimensionName(ClassifySetting1D.DIMENSION_NAME_Y);
        }
        setting.setVariableName(var);
        return new ClassifySetting[]{setting};
    }

    public boolean isActonComboBox() {
        return actonComboBox;
    }

    public void setActonComboBox(boolean actonComboBox) {
        this.actonComboBox = actonComboBox;
    }

    /**
     *  
     *  
     */
    class MyComboBox extends TpComboBox{
        /**
         * setSelectedItem without fire action events
         * @param anObject
         */
        public void setSelectedItemQuitely(Object anObject) {
            DefaultComboBoxModel model=(DefaultComboBoxModel) dataModel;
            boolean found = false;
            for (int i = 0; i < dataModel.getSize(); i++) {
                if (anObject.equals(dataModel.getElementAt(i))) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                return;
            }

            model.setSelectedItem(anObject);
        }


    }


}
